package Cordiali_Es2;


import arjuna.JavaSim.Simulation.*;
import arjuna.JavaSim.Distributions.*;

import java.io.IOException;
import java.util.Comparator;
import java.util.PriorityQueue;


import arjuna.JavaSim.Simulation.SimulationException;


public class Server extends SimulationProcess {
		

	
	public enum QueueType {PT,PS,FIFO};

	public RandomStream STime;
	private OutputAction onOut;
	//private boolean operational;
	//private boolean working;
	private QueueType qt;
	private PriorityQueue<User> usersQueue; 
//	private User J;

	public Server(RandomStream rand, QueueType qt, OutputAction onOut) {
		this.onOut=onOut;
		STime = rand;
		this.qt=qt;
		switch (qt)
		{
		case PS:
		case PT:
			usersQueue = new PriorityQueue<User>(1, 
					new Comparator<User>() {
						@Override
						public int compare(User o1, User o2) {
							return o1.currentJobTime<o2.currentJobTime?-1:1;
						}				
					});
			break;
		default:
			usersQueue = new PriorityQueue<User>(10,					
					new Comparator<User>() {
					@Override
					public int compare(User o1, User o2) {
						return o1.currentArrivalTime<o2.currentArrivalTime?-1:1;
					}				
				});
		}
	}

	double lastArrivalTime = 0;
	double lastTickTime=CurrentTime();
	public void run() {		
		try {
			while(true) {
				while(!usersQueue.isEmpty())
				{
					switch(qt)
					{
					case PS:
						double elapsedTime=CurrentTime()-lastTickTime;	
						lastTickTime=CurrentTime();
						for(User u : usersQueue)
						{
							u.currentJobTime-=elapsedTime/usersQueue.size();
							//u.serviceTimeS1+=elapsedTime;
						}
						while(!usersQueue.isEmpty())
						{
							User u = usersQueue.peek();
							if(u.currentJobTime>Math.pow(10, -10))
							{
								Hold(u.currentJobTime*usersQueue.size());
								break;
							}
							u = usersQueue.poll();
							u.markFinishServed(this);
							onOut.onOutput(u);
							//ECommerceShop.pool.collectUserStatistics(u);
							//System.out.println(CurrentTime()+" Served");
						}
						
					break;
					default:
						User u = usersQueue.poll();					
						u.markStartServed(this);
						Hold(u.currentJobTime);
						u.markFinishServed(this);
						onOut.onOutput(u);
						
						if(u.currentArrivalTime<lastArrivalTime)
							System.out.println("Noooooooooooo");
						lastArrivalTime=u.currentArrivalTime;
						//ECommerceShop.pool.collectUserStatistics(u);
						//System.out.println(CurrentTime()+" Served");
					}
				}
				Passivate();
			}
		} catch (SimulationException e) {
			e.printStackTrace();
		} catch (RestartException e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public void Activate() throws SimulationException, RestartException
	{
		if(passivated())
		{
			lastTickTime=CurrentTime();
			super.Activate();
		}
	}
	
	public void addToQueue(User u)
	{
		try {
			u.markArrived(this);
			u.currentJobTime=STime.getNumber();
			usersQueue.add(u);
			Activate();
		} catch (ArithmeticException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SimulationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RestartException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
	}	
	
	public int queueLength()
	{
		switch(qt)
		{
			case PS: return 0;
			default: return usersQueue.size();
		}
	}

	public int inService()
	{
		switch(qt)
		{
			case PS: return usersQueue.size();
			default: return passivated()?0:1;
		}
	}
	
};
